import type { ShallowReactive } from "vue";
import { getRandomId } from "./utils";
import { BaseModule } from "./module";
import { BaseView } from "./view";

export class ContextScene<
    M extends Record<string, new (...args: unknown[]) => BaseModule>,
    V extends Record<string, new (...args: unknown[]) => BaseView>
> {
    protected _id: string = getRandomId();
    /** 唯一标识 */
    get id() {
        return this._id;
    }
    /** 模块原型 */
    protected moduleProto: { [K in keyof M]: M[K] };
    /** 模块 */
    modules: ShallowReactive<Record<string, InstanceType<M[keyof M]>>> = shallowReactive({});
    /** 视图原型 */
    protected viewProto: { [K in keyof V]: V[K] };
    /** 视图 */
    views: ShallowReactive<Record<string, InstanceType<V[keyof V]>>> = shallowReactive({});
    /** 刷新标志 */
    protected _refreshFlag: Ref<boolean> = ref(true);
    get refreshFlag() {
        return this._refreshFlag;
    }

    /**
     * @param moduleProto 模块原型
     * @param viewProto 视图原型
     */
    constructor(moduleProto: M, viewProto: V) {
        this.moduleProto = moduleProto;
        this.viewProto = viewProto;
    }

    /** 刷新 */
    async refresh() {
        this._refreshFlag.value = false;
        return await new Promise((resolve) => {
            setTimeout(() => {
                this._refreshFlag.value = true;
                resolve(null);
            });
        });
    }
    /** 初始化 */
    async init() {
        await this.refresh();
    }
    /** 销毁 */
    async destroy() {
        for (const key in this.modules) {
            const module = this.modules[key];
            if (module) {
                await module.destroy();
            }
        }
        for (const key in this.views) {
            const view = this.views[key];
            if (view) {
                view.destroy();
            }
        }
        this.modules = {};
        this.views = {};
    }
    /**
     * 根据 key 和 type 获取模块，如果不存在则抛出异常
     * @param key 模块的键名
     * @param type 模块的类名
     * @returns 模块实例
     */
    getModule<K extends keyof M>(key: string, type: K): InstanceType<M[K]> {
        const module = this.tryGetModule(key, type);
        if (!module) {
            throw new Error(`Module ${key} not found`);
        }
        return module;
    }
    /**
     * 尝试根据 key 和 type 获取模块，如果不存在则返回 undefined
     * @param key 模块的键名
     * @param type 模块的类名
     * @returns 模块实例或 undefined
     */
    tryGetModule<K extends keyof M>(key: string, type: K): InstanceType<M[K]> | undefined {
        const module = this.modules[key];
        const ModuleClass = this.moduleProto[type];
        if (module && ModuleClass) {
            return module as InstanceType<M[K]>;
        }
        return undefined;
    }
    /**
     * 创建模块
     * @param type 模块的类名
     * @param config 模块的配置
     * @param init 是否立即初始化
     * @returns 模块实例
     */
    async createModule<K extends keyof M>(
        type: K,
        config: Parameters<InstanceType<M[K]>["init"]>[0],
        init: boolean = true
    ): Promise<InstanceType<M[K]>> {
        const ModuleClass = this.moduleProto[type];
        const module = new ModuleClass() as InstanceType<M[K]>;
        module.config = config;
        if (init) {
            await module.init(config);
        }
        this.modules[module.id] = module;
        return module;
    }
    /** 获取未初始化的模块 id 列表 */
    getUninitedModuleIds(): string[] {
        return Object.values(this.modules)
            .filter((m) => !m.inited)
            .map((m) => m.id);
    }
    /**
     * 根据 key 和 type 获取视图，如果不存在则抛出异常
     * @param key 视图的键名
     * @param type 视图的类名
     * @returns 视图实例
     */
    getView<K extends keyof V>(key: string, type: K): InstanceType<V[K]> {
        const view = this.tryGetView(key, type);
        if (!view) {
            throw new Error(`View ${key} not found`);
        }
        return view;
    }
    /**
     * 尝试根据 key 和 type 获取视图，如果不存在则返回 undefined
     * @param key 视图的键名
     * @param type 视图的类名
     * @returns 视图实例或 undefined
     */
    tryGetView<K extends keyof V>(key: string, type: K): InstanceType<V[K]> | undefined {
        const view = this.views[key];
        const ViewClass = this.viewProto[type];
        if (view && ViewClass) {
            return view as InstanceType<V[K]>;
        }
        return undefined;
    }
    /**
     * 创建视图
     * @param type 视图的类名
     * @param config 视图的配置
     * @param externalModules 视图依赖的外部模块
     * @param init 是否立即初始化
     * @returns 视图实例
     */
    async createView<K extends keyof V, P extends Parameters<InstanceType<V[K]>["init"]>>(
        type: K,
        config: P[0],
        externalModules: P[1],
        init: boolean = true
    ): Promise<InstanceType<V[K]>> {
        const ViewClass = this.viewProto[type];
        const view = new ViewClass() as InstanceType<V[K]>;
        if (init) {
            await view.init(config, externalModules);
        }
        this.views[view.id] = view;
        return view;
    }
    /** 获取未初始化的视图 id 列表 */
    getUninitedViewIds(): string[] {
        return Object.values(this.views)
            .filter((v) => !v.inited)
            .map((v) => v.id);
    }
}
